home *** CD-ROM | disk | FTP | other *** search
/ Shareware Grab Bag / Shareware Grab Bag.iso / 007 / vtkerma2.arc / MSXIBM.ASM < prev    next >
Assembly Source File  |  1986-02-13  |  32KB  |  1,282 lines

  1.     PAGE 59, 132
  2.  
  3.     TITLE MSXIBM -- Machine dependent module for IBM-PC, except Terminal
  4.  
  5. ; Update 4 Jan 86
  6.  
  7. IF1
  8.  %OUT >> Starting pass 1
  9. ELSE
  10.  %OUT >> Starting pass 2
  11. ENDIF
  12.  
  13.     PUBLIC SerIni_PC, SerRst_PC, ClrBuf_PC, OutChr_PC, Coms_PC
  14. ;    PUBLIC VTS_PC
  15.     PUBLIC DoDel_PC, CtlU_PC, CmBlnk_PC, Locate_PC, PrtChr_PC, DoBaud_PC
  16.     PUBLIC ClearL_PC, DoDisk_PC, GetBaud_PC, Beep_PC
  17.     PUBLIC PutHlp_PC, PutMod_PC, PutErr_PC, ClrMod_PC, PosCur_PC
  18.     PUBLIC SendBr_PC, SetKTab_PC, SetKHlp_PC, LclIni_PC, ShowKey_PC
  19.     PUBLIC Which_card, Drop_DTR_PC, Which_page, Beam_Off, Beam_On
  20.     PUBLIC Set_up_video_card_pointers, CRT_Mode
  21.  
  22.     INCLUDE msdefs.h
  23.  
  24. false    EQU 0
  25. true    EQU 1
  26. Screen    EQU 10h            ; BIOS screen call
  27.  
  28. XOFF_trigger_count EQU BufSiz*2 / 3 ; High point = 2/3 of buffer full
  29.  
  30. Mode_control_port EQU 3D8h    ; CRT mode control port
  31. Video_enable EQU 8        ; Display enable flag
  32.  
  33. Number_of_rows EQU 24        ; Length in rows
  34. Number_of_columns EQU 80    ; Width in characters
  35. Highest_row EQU Number_of_rows-1; Highest row number
  36. Highest_column EQU Number_of_columns-1 ; Highest column number
  37. Number_of_rows_PC EQU 25    ; Length in rows including mode line
  38.  
  39. ; constants used by serial port handler
  40.  
  41. BRKBIT    EQU 40h            ; Send-break bit
  42. TIMER    EQU 40h            ; Use to issue short beep
  43. PORT_B    EQU 61h            ; Port B address
  44. MCONF    EQU 11h            ; Machine configuration
  45. KEYB    EQU 16h
  46. BIOS    EQU 10h
  47.  
  48. MDMDAT1    EQU 03F8h        ; Address of modem port 1 data register
  49. MDMSTS1    EQU 03FDh        ; Address of modem port    1 status register
  50. MDMCOM1    EQU 03FBh        ; Address of modem port 1 command register
  51.  
  52. MDMDAT2    EQU 02F8h        ; Port 2 address register
  53. MDMSTS2    EQU 02FDh        ; Port 2 status register
  54. MDMCOM2    EQU 02FBh        ; Port 2 command register
  55.  
  56. MDMINP    EQU 1            ; Input ready bit
  57.  
  58. MDMINTV    EQU 0030h        ; Address of modem port interrupt vector
  59. MDINTV2 EQU 002Ch        ; Address for port 2
  60.  
  61. MDMINTO    EQU 0EFh        ; Mask to enable interrupt for modem port
  62. MDINTO2 EQU 0F7h        ; Enable interrupt level 3
  63.  
  64. MDMINTC    EQU 010h        ; Bit to set to disable interrupts for modem
  65. MDINTC2 EQU 008h        ; Disable IRQ3
  66.  
  67. INTCONT    EQU 0021h        ; Address of 8259 interrupt controller ICW2-3
  68. INTCON1    EQU 0020h        ; Address of 8259 ICW1
  69.  
  70. EOICOM    EQU 0064h        ; End of interrupt
  71. EOICOM2    EQU 0063h        ; End of interrupt for COM2
  72.  
  73.  
  74. ; external variables used:
  75. ; drives - # of disk drives on system
  76. ; flags - global flags as per flginfo structure defined in pcdefs
  77. ; trans - global transmission parameters, trinfo struct defined in pcdefs
  78. ; portval - pointer to current portinfo structure (currently either port1
  79. ;    or port2)
  80. ; port1, port2 - portinfo structures for the corresponding ports
  81.  
  82. ; global variables defined in this module:
  83. ; xofsnt, xofrcv - tell whether we saw or sent an xoff
  84. ; setktab - keyword table for redefining keys (should contain a 0 if
  85. ;    not implemented)
  86. ; setkhlp - help for setktab
  87.  
  88. DataS    SEGMENT    PUBLIC 'DataS'
  89.  
  90.     EXTRN drives:byte,flags:byte, trans:byte, PC_Subtype:BYTE
  91.     EXTRN portval:word, port1:byte, port2:byte
  92.     EXTRN Count:WORD, XofSnt:BYTE, Force_mono:BYTE, Force_card:BYTE
  93.     EXTRN Source:BYTE, SrcPnt:WORD, PC_Type:BYTE
  94.  
  95.     PUBLIC Video_page_addresses
  96.  
  97. Video_page_addresses LABEL WORD
  98.     DW 0B800h        ; Page zero
  99.     DW 0B900h        ; Page one
  100.  
  101. SetKTab_PC DB 12
  102.     mkeyw    'BACKSPACE',0eh
  103.     mkeyw    'F1',3bh
  104.     mkeyw    'F2',3ch
  105.     mkeyw    'F3',3dh
  106.     mkeyw    'F4',3eh
  107.     mkeyw    'F5',3fh
  108.     mkeyw    'F6',40h
  109.     mkeyw    'F7',41h
  110.     mkeyw    'F8',42h
  111.     mkeyw    'F9',43h
  112.     mkeyw    'F10',44h
  113.     mkeyw    'SCAN',-1
  114.  
  115. SetKHlp_PC DB cr,lf,'Keyname: backspace, f1, ... f10, or "SCAN" followed by '
  116.     DB 'decimal scan code$'
  117. brkval    DB 0            ; What to send for a break
  118. brkadr    DW 0            ; Where to send it
  119. modem    mdminfo    <MDMDAT1,MDMSTS1,MDMCOM1,MDMINTO,MDMINTC,EOICOM,MDMINTV>
  120. erms20    DB '? Warning:  System has no disk drives', Cr, Lf, '$'
  121. erms40    DB '? Warning:  Unrecognized baud rate', Cr, Lf, '$'
  122. badbd    DB 'Unimplemented baud rate', Cr, Lf, '$'
  123. No_memory DB '? Not enough memory for program to run (screen management)'
  124.     DB Cr, Lf, '$'
  125. crlf    DB cr,lf,'$'
  126. delstr  DB BS,' ',BS,'$'    ; Delete string. [21d]
  127. clrlin  DB cr,'$'        ; Clear line (just the cr part)
  128. savsci    DW ?            ; Save for serial port interrupt vector. [14]
  129. savscs    DW ?            ; Ditto.  [14]
  130. savbr1    DW ?            ; "Break" interrupt vector. [25]
  131. savbr2    DW ?            ; Ditto. [25]
  132. portin    DB 0            ; Has comm port been initialized. [21c]
  133. xofrcv    DB 0            ; Say if we received an XOFF
  134. tmp    DB ?,'$'
  135. temp    DW 0
  136. temp1    DW ?            ; Temporary storage
  137. temp2    DW ?            ; Temporary storage
  138.  
  139. CRT_Mode DB 7            ; Crt mode for video card
  140. Which_page DB 0            ; Video page number
  141. Screen_pointer DW 0B000h    ; Pointer to real screen memory
  142.  
  143. Beam_status DB ?        ; Place to hold CRT status reg value
  144.  
  145. ontab    DB 02H            ; Two entries
  146.     DB 03H,'OFF$'        ; Should be alphabetized.  [19a]
  147.     DW 00H
  148.     DB 02H,'ON$'
  149.     DW 01H
  150.  
  151. comptab    DB 04H
  152.     DB 01H,'1$'
  153.     DW 01H
  154.     DB 01H,'2$'
  155.     DW 00H
  156.     DB 04H,'COM1$'
  157.     DW 01H
  158.     DB 04H,'COM2$'
  159.     DW 00H
  160.  
  161. ; this table is indexed by the baud rate definitions given in
  162. ; pcdefs.  Unsupported baud rates should contain FF
  163.  
  164. bddat    label    word
  165.     DW 0FFH            ; 45.5 baud  -- Not supported
  166.     DW 900H            ; 50 baud
  167.     DW 600H            ; 75 baud
  168.     DW 417H            ; 110 baud
  169.     DW 359H            ; 134.5 baud
  170.     DW 300H            ; 150 baud
  171.     DW 180H            ; 300 baud
  172.     DW 0C0H            ; 600 baud
  173.     DW 60H            ; 1200 baud
  174.     DW 40H            ; 1800 baud
  175.     DW 3AH            ; 2000 baud
  176.     DW 30H            ; 2400 baud
  177.     DW 18H            ; 4800 baud
  178.     DW 0CH            ; 9600 baud
  179.     DW 06h            ; 19200 baud
  180.     DW 03h            ; 38400 baud
  181.     DW 05h            ; 23040 baud
  182.  
  183. ; variables for serial interrupt handler
  184.  
  185. savesi    DW 0            ; Save SI register here
  186. telflg    DB 0            ; Are we acting as a terminal
  187. mst    DW 0            ; Modem status address
  188. mdat    DW 0            ; Modem data address
  189. mdeoi    DB 0            ; End-of-Interrupt value
  190.  
  191. rbtrn    DB 7fH            ; rubout
  192.  
  193. shkbuf    DB 300 dup (?)        ; room for definition
  194. shkmsg    DB '  Scan code: '
  195. shkmln    EQU $-shkmsg
  196. shkms1    DB cr,lf,'  Definition: '
  197. shkm1ln    EQU $-shkms1
  198.  
  199. DataS    ENDS
  200.  
  201. Code    SEGMENT    PUBLIC
  202.  
  203.     EXTRN Comnd:near, dopar:near, defkey:near, gss:near
  204.     EXTRN Set_up_dynamic_memory:NEAR, Exit2:NEAR, NoInt:NEAR, OkInt:NEAR
  205.     EXTRN Write_to_standard_output:NEAR
  206.  
  207.     ASSUME cs:Code, ds:DataS
  208.  
  209. Which_card DB 0            ; 0 for mono, 1 for color, 2 for EGA
  210.  
  211. ; local initialization
  212.  
  213. LclIni_PC    proc    near
  214.  
  215.     call Set_up_dynamic_memory ; Try to get memory
  216.      jnc LCL_0
  217.  
  218.     mov ah, PrStr        ; Code to type message
  219.     mov dx, OFFSET No_memory ; Complain about lack of memory
  220.     int Dos            ; Display it
  221.  
  222.     call Exit2        ; Bomb out also
  223.      nop
  224.      nop
  225.      nop
  226.  
  227.     ret            ; Return to main program
  228.  
  229. LCL_0:    mov    ax,0eH        ; scan code for arrow key
  230.     mov    si,offset rbtrn    ; translate to rubout
  231.     mov    cx,1        ; one char translation
  232.     call    defkey
  233.     mov brkval,BRKBIT    ; What to send for a break
  234.     mov ax,modem.mdcom    ; Where to send it
  235.     mov brkadr,ax
  236.  
  237.     call Set_up_video_card_pointers
  238.     jmp Go_to_page_zero
  239.  
  240. LclIni_PC    endp
  241.  
  242.  
  243. Set_up_video_card_pointers PROC
  244.  
  245.     mov ah, 15        ; Code to read current video mode
  246.     int Screen        ; Read it
  247.  
  248.     mov CRT_Mode, al    ; Save crt mode
  249.  
  250.     sub ah, ah        ; Set flag for mono
  251.     mov Which_page, ah    ; Zero the page number
  252.  
  253.     cmp Force_card, 0FFh    ; Are we forcing some card type?
  254.      je SUV_0        ;  No, keep checking
  255.  
  256.     mov ah, Force_card    ; Pick up forced value
  257.     mov Which_card, ah    ; Save it
  258.     ret            ; That's it
  259.  
  260. SUV_0:    cmp al, 7        ; Is it really color?
  261.      je SUV_1        ;  Ok, it is monochrome
  262.  
  263.     mov ah, 1        ; Flag for color card
  264.  
  265. SUV_1:    mov Which_card, ah    ; Remember which card we are using
  266.     cmp ah, 1        ; Did we just decide that this is a color card?
  267.      je Check_for_EGA    ; See if we are on the Enhanced card
  268.  
  269.     ret            ; That's it
  270.  
  271. Set_up_video_card_pointers ENDP
  272.  
  273.  
  274. ; See if we are using the Enhanced Graphics Adapter
  275.  
  276. Check_for_EGA PROC
  277.  
  278.     cmp PC_Type, 0        ; We won't even bother without PC-DOS
  279.      jne CEG_Done        ;  Not running PC-DOS, assume not EGA
  280.  
  281.     cmp PC_Subtype, 0    ; Are we on a normal PC?
  282.      je CEG_PC        ;  Yes
  283.  
  284.     cmp PC_Subtype, 1    ; Are we on an XT?
  285.      je CEG_XT        ;  Yes
  286.  
  287.     cmp PC_Subtype, 4    ; ... or a Portable (same motherboard as XT)?
  288.      je CEG_XT        ;  Yes
  289.  
  290.     cmp PC_Subtype, 3    ; Are we on an AT?
  291.      je CEG_AT        ;  Yes
  292.  
  293. ;    jmp CEG_Done        ; No way of knowing about EGA, assume CGA
  294.     jmp CEG_Assume_EGA    ; Try default of EGA for non-PC type machines
  295.  
  296.                 ; What this really means is that we don't
  297.                 ;  assume working BIOS support for our "normal"
  298.                 ;  complicated color screen update
  299.                 ; This certainly speeds up the screen on
  300.                 ;  liquid crystal (and other ...) displays
  301.  
  302. ; Regular PC -- give it a shot!
  303.  
  304. CEG_PC:    call NoInt        ; No ints during this
  305.     in al, 61h        ; This port allows access to port 60h
  306.     mov bl, al        ; Save the original value from port 61h
  307.     or al, 80h        ; Turn on the bit making port 60h be switches
  308.     out 61h, al        ; Set this up
  309.     in al, 60h        ; Read system board switch bank 1
  310.     xchg al, bl        ; Save the switch settings, get back original
  311.                 ;  value from port 61h
  312.     out 61h, al        ; Restore original value
  313.     call OkInt        ; Interrupts are permitted again
  314.     mov al, bl        ; Get back the switch settings
  315.     jmp SHORT CEG_Common_code ; Join common code
  316.  
  317. ; PC/XT -- have to use a slightly different method
  318.  
  319. CEG_XT:    call NoInt        ; No interrupts during this stuff
  320.     in al, 61h        ; This port controls how we read port 62h
  321.     mov bl, al        ; Save the original value from port 61h
  322.     or al, 40h        ; Force this bit on so we read the high half
  323.     out 61h, al        ; Set this up
  324.     in al, 62h        ; Read the high half of SW 1
  325.     xchg al, bl        ; Save the switch settings, get back original
  326.                 ;  value from port 61h
  327.     out 61h, al        ; Restore original value
  328.     call OkInt        ; Interrupts are permitted again
  329.     mov al, bl        ; Get back the switch settings
  330.     jmp SHORT CEG_Common_code ; Join common code
  331.  
  332. ; PC AT, look into CMOS battery powered RAM for configuration info
  333.  
  334. CEG_AT:    mov al, 14h        ; CMOS register holding equip flags
  335.     out 70h, al        ; Tell CMOS chip which register we want
  336.     in al, 71h        ; Read the equip flags
  337.  
  338.     PUBLIC CEG_Common_code
  339.  
  340. CEG_Common_code:
  341.     test al, 30h        ; Are either of these switches set?
  342.      jnz CEG_Done        ;  Not EGA
  343.  
  344. CEG_Assume_EGA:
  345.     mov Which_card, 2    ; Code for EGA
  346.  
  347. CEG_Done: ret            ; Go home
  348.  
  349. Check_for_EGA ENDP
  350.  
  351.  
  352.     PUBLIC Switch_video_pages
  353.  
  354. Switch_video_pages:
  355.     mov ax, 0B000h        ; Address of monochrome card
  356.     cmp Which_card, 0    ; Monochrome card?
  357.      je SVP_Set        ;  Yes
  358.  
  359.     mov ax, 0B800h        ; Address of color card
  360.     cmp Which_card, 2    ; EGA?
  361.      je SVP_Set        ;  Yes
  362.  
  363. ; True color card, really switch pages
  364.  
  365.     mov al, 1        ; Get a one
  366.     sub al, Which_page    ; 1 minus 0 = 1, 1 minus 1 = 0
  367.     mov Which_page, al    ; Store for next time
  368.     mov ah, 5        ; Code to switch video pages
  369.     int Screen        ; Tell ROM BIOS to switch pages now
  370.  
  371.     mov bl, Which_page    ; Get number of page we are on
  372.     sub bh, bh        ; Zero top half of word
  373.     shl bx, 1        ; Double for word offset
  374.     mov ax, Video_page_addresses[bx] ; Address of the screen memory
  375.  
  376. SVP_Set:
  377.     mov Screen_pointer, ax    ; Set up this pointer
  378.     ret            ; Done here
  379.  
  380.     PUBLIC Go_to_page_zero
  381.  
  382. Go_to_page_zero:
  383.  
  384.     sub al, al        ; Get a zero
  385.     mov Which_page, al    ; Store it as the page we are on
  386.     mov ah, 5        ; Code to switch video pages
  387.     int Screen        ; Tell ROM BIOS to switch pages now
  388.  
  389.     mov ax, 0B000h        ; Address of monochrome card's only page
  390.     cmp Which_card, 0    ; Mono card?
  391.      je PG0_Mono        ;  Monochrome
  392.  
  393.     mov ax, 0B800h        ; Addr of color card page zero (maybe EGA)
  394.  
  395. PG0_Mono:
  396.     mov Screen_pointer, ax    ; Set up pointer
  397.     ret
  398.  
  399.     PUBLIC Blank_current_page
  400.  
  401. Blank_current_page:
  402.     mov ax, 600h        ; Code to blank entire window
  403.     mov bh, 7        ; Normal video attribute
  404.     sub cx, cx        ; Make a zero as upper left corner
  405.     mov dx, (100h * (Number_of_rows_PC - 1) ) + Highest_column
  406.                 ; Use real lower right corner of screen
  407.     int Screen        ; Ask BIOS to blank it for us
  408.     ret            ; Done here
  409.  
  410.  
  411. ; Turn video beam off and on to prevent screen snow on color card
  412.  
  413. Beam_Off PROC
  414.  
  415.     cmp CRT_Mode, 7        ; BW?
  416.      je BOF_1        ;  Yes
  417.  
  418.     push es            ; Save reg
  419.     sub ax, ax        ; Make a zero
  420.     mov es, ax        ; Address low memory
  421.     mov al, es:[465h]    ; Pick up DOS's value for this
  422.     mov Beam_status, al    ; Save for later
  423.     and al, NOT Video_enable ; Mask off the video bit
  424.     mov dx, Mode_control_port ; Address of CRT control port
  425.     out dx, al        ; Turn off the video now
  426.     pop es            ; Restore saved reg
  427.  
  428. BOF_1:    ret
  429.  
  430. Beam_Off ENDP
  431.  
  432. Beam_On PROC
  433.  
  434.     cmp CRT_Mode, 7        ; BW?
  435.      je BON_1        ;  Yes
  436.  
  437.     mov al, Beam_status    ; Pick up saved beam state
  438.     mov dx, Mode_control_port ; Address of CRT control port
  439.     out dx, al        ; Restore the old state
  440.  
  441. BON_1:    ret
  442.  
  443. Beam_On ENDP
  444.  
  445.  
  446. ; this is called by Kermit initialization.  It checks the
  447. ; number of disks on the system, sets the drives variable
  448. ; appropriately.  Returns normally
  449.  
  450. DoDisk_PC    PROC    NEAR
  451.     int mconf            ; Get equipment configuration
  452.     mov ah,al            ; Store AL value for a bit
  453.     and al,01H            ; First, look at bit 0
  454.     jz dodsk0            ; No disk drives -- forget it
  455.     mov al,ah            ; Get back original value
  456.     mov cl,6            ; Shift over bits 6 and 7
  457.     shr al,cl            ; To positions 0 and 1
  458.     inc al                ; Want 1 thru 4 (not 0 thru 3)
  459.     mov drives,al            ; Remember how many
  460.     ret
  461. dodsk0:    mov ah,prstr            ; Print a warning message
  462.     mov dx,offset erms20        ; I'm not sure if things will
  463.     int dos                ; work with only a cassette
  464.     mov drives,0            ; Say there aren't any drives
  465.     ret
  466. DoDisk_PC    ENDP
  467.  
  468. ; show the definition of a key.  The terminal argument block (which contains
  469. ; the address and length of the definition tables) is passed in ax
  470. ; Returns a string to print in AX, length of same in CX
  471. ; Returns normally
  472. ShowKey_PC    proc    near
  473.     push    es
  474.     push    ax        ; save the ptr
  475.     mov    bx,ds
  476.     mov    es,bx        ; address data segment
  477.     cld
  478. showk1:    xor    ah,ah
  479.     int    keyb        ; read a char
  480.     push    ax        ; save the character
  481.     call    gss        ; get shift state
  482.     pop    bx
  483.     mov    ah,al        ; shift state to ah
  484.     mov    al,bh        ; scan code to al
  485.     push    ax        ; remember scan code
  486.     mov    di,offset shkbuf
  487.     mov    si,offset shkmsg
  488.     mov    cx,shkmln
  489.     rep    movsb        ; copy in initial message
  490.     call    nout        ; write out scan code
  491.     mov    si,offset shkms1
  492.     mov    cx,shkm1ln    ; second message
  493.     rep    movsb
  494.     pop    ax        ; get scan code back
  495.     pop    bx        ; and terminal arg block
  496.     mov    cx,[bx].klen    ; and length
  497.     jcxz    showk2        ; no table, not defined
  498.     push    di        ; remember output ptr
  499.     mov    di,[bx].ktab    ; get key table
  500.     repne    scasw        ; search for a definition for this
  501.     mov    si,di        ; remember result ptr
  502.     pop    di        ; get output ptr back
  503.     jne    showk2        ; not defined, forget it
  504.     sub    si,[bx].ktab    ; compute offset from beginning
  505.     sub    si,2        ; minus 2 for pre-increment
  506.     add    si,[bx].krpl    ; get index into replacement table
  507.     mov    si,[si]        ; pick up replacement
  508.     mov    cl,[si]        ; get length
  509.     mov    ch,0
  510.     inc    si
  511.     rep    movsb        ; copy into buffer
  512. showk2:    mov    ax,offset shkbuf ; this is buffer
  513.     mov    cx,di
  514.     sub    cx,ax        ; length
  515.     pop    es
  516.     ret            ; and return
  517. ShowKey_PC    endp
  518.  
  519. ; Clear the input buffer. This throws away all the characters in the
  520. ; serial interrupt buffer.  This is particularly important when
  521. ; talking to servers, since NAKs can accumulate in the buffer
  522. ; Returns normally
  523.  
  524. ClrBuf_PC    PROC    NEAR
  525.     call NoInt        ; No interrupts during this
  526.     mov ax,offset source
  527.     mov srcpnt,ax
  528.     mov savesi,ax
  529.     mov count,0
  530.     call OkInt
  531.     ret
  532. ClrBuf_PC    ENDP
  533.  
  534. ; Clear to the end of the current line.  Returns normally
  535.  
  536. ClearL_PC    PROC    NEAR
  537.     mov ah,3        ; Clear to end of line
  538.     mov bh,0
  539.     int bios        ; Get current cursor position
  540.     mov cx,dx
  541.     mov dl,79
  542.     mov ah,7
  543.     mov al,0
  544.     mov bh,7
  545.     int bios
  546.     ret
  547. ClearL_PC    ENDP
  548.  
  549. ; Put the char in AH to the serial port.  This assumes the
  550. ; port has been initialized.  Should honor xon/xoff.  Skip returns on
  551. ; success, returns normally if the character cannot be written
  552.  
  553. OutChr_PC:
  554.     push cx            ; Save initial cx
  555.     mov bp,portval
  556.     cmp ds:[bp].floflg,0    ; Are we doing flow control
  557.      je outch2        ;  No, just continue
  558.  
  559.     sti            ; Make sure interrupts are ok
  560.     mov cx, 4        ; Perform the inner loop this many times
  561.  
  562. outcha:    push cx            ; Save outer loop counter
  563.     xor cx, cx        ; Clear inner loop counter
  564.  
  565. outch1:    cmp xofrcv, true    ; Are we being held?
  566.      jne outchb        ;  No - it's OK to go on
  567.  
  568.     loop outch1        ; Held, try for a while (inner loop)
  569.  
  570.     pop cx            ; Restore outer loop counter
  571.     loop outcha        ; Restart inner loop
  572.  
  573.     mov xofrcv, false    ; Timed out, force it off and fall thru
  574.     jmp SHORT outch2    ; Join common code
  575.  
  576. outchb:    pop cx            ; Flush saved outer loop counter
  577.  
  578. outch2:    push dx            ; Save register
  579.     sub cx,cx
  580.     mov al,ah        ; Parity routine works on AL
  581.     call dopar        ; Set parity appropriately
  582.     mov ah,al        ; Don't overwrite character with status
  583.     mov dx,modem.mdstat    ; Get port status
  584. outch3:    in al,dx
  585.     test al,20H        ; Transmitter ready?
  586.     jnz outch4        ; Yes
  587.     loop outch3
  588.      jmp outch5        ; Timeout
  589. outch4:    mov al,ah        ; Now send it out
  590.     mov dx,modem.mddat
  591.     out dx,al
  592.     pop dx
  593.     pop cx
  594.     jmp rskp
  595. outch5:    pop dx
  596.     pop cx
  597.     ret
  598.  
  599. ; This routine blanks the screen.  Returns normally
  600.  
  601. CmBlnk_PC    PROC    NEAR        ; This is stolen from the IBM example
  602.     mov cx,0
  603.     mov dx,184FH
  604.     mov bh,7
  605.     mov ax,600H
  606.     int bios
  607.     ret
  608. CmBlnk_PC  ENDP
  609.  
  610. ; Locate_PC: homes the cursor.  Returns normally
  611.  
  612. Locate_PC  PROC    NEAR
  613.     mov dx,0        ; Go to top left corner of screen
  614.     jmp PosCur_PC
  615. Locate_PC  ENDP
  616.  
  617. ; Write a line in inverse video (or Blue-on-White) at the
  618. ;    bottom of the screen...  Ptr to the line is passed in dx,
  619. ;    line is terminated by a $.  Returns normally
  620.  
  621. PutMod_PC PROC
  622.  
  623.     mov bh,70h        ; Inverse video
  624.     cmp Force_mono, 0    ; Mono forced?
  625.      jne PMD_1        ;  Yes
  626.  
  627.     cmp Which_card, 0    ; Monochrome card?
  628.      je PMD_1        ;  Yes
  629.  
  630.     mov bh, 71h        ; Use Blue on White on color card
  631.  
  632. PMD_1:    jmp Mode_common        ; Use common code
  633.  
  634. PutMod_PC ENDP
  635.  
  636. ; Write a line in inverse video or Red-on-White at the
  637. ;    bottom of the screen...  Ptr to line is passed in dx,
  638. ;    line is terminated by a $.  Returns normally
  639.  
  640. PutErr_PC PROC
  641.  
  642.     mov bh,70h        ; Inverse video
  643.     cmp Force_mono, 0    ; Mono forced?
  644.      jne PER_1        ;  Yes
  645.  
  646.     cmp Which_card, 0    ; Monochrome card?
  647.      je PER_1        ;  Yes
  648.  
  649.     mov bh, 74h        ; Use Red on White on color card
  650.  
  651. PER_1:    jmp Mode_common        ; Join common code
  652.  
  653. PutErr_PC ENDP
  654.  
  655. ; Common code for PutMod_PC and PutErr_PC
  656.  
  657. Mode_common PROC
  658.  
  659.     push    dx        ; preserve message
  660.     mov    cx,1800h
  661.     mov    dx,184fh
  662.     mov    ax,600h        ; scroll to clear the line
  663.     int    bios        ; Do it
  664.     mov    dx,1800h    ; now address line 24
  665.     call    PosCur_PC
  666.     pop    dx        ; get message back
  667.     call Write_to_standard_output ; Use standard routine to do this
  668. ;    mov    ah,prstr
  669. ;    int    dos        ; write it out
  670.     ret            ; and return
  671.  
  672. Mode_common ENDP
  673.  
  674. ; clear the mode line written by PutMod_PC.  Returns normally
  675. ClrMod_PC    proc    near
  676.     mov    cx,1800h
  677.     mov    dx,184fh
  678.     mov    ax,600h
  679.     mov    bh,7h
  680.     int    bios
  681.     ret
  682. ClrMod_PC    endp
  683.  
  684. ; put a help message on the screen.  This one uses reverse video..
  685. ; pass the message in ax, terminated by a null.  Returns normally
  686. PutHlp_PC    proc    near
  687.     push    ax        ; preserve this
  688.     cld            ; Forwards
  689.     mov    si,ax        ; point to it
  690.     mov    dh,0        ; init counter
  691. puthl1:    lodsb            ; get a byte
  692.     cmp    al,lf        ; linefeed?
  693.     jne    puthl2        ; no, keep going
  694.     inc    dh        ; count it
  695.     jmp    puthl1        ; and keep looping
  696. puthl2:    cmp    al,0        ; end of string?
  697.     jne    puthl1        ; no, keep going
  698.     mov    ax,600h        ; scroll to clear window
  699.     xor    cx,cx        ; from top left
  700.     mov    dl,4fh        ; to bottom right of needed piece
  701.     mov    bh, 70h        ; Inverse video
  702.     cmp    Force_mono, 0    ; Mono forced?
  703.      jne     PHP_1        ;  Yes
  704.  
  705.     cmp    Which_card, 0    ; Monochrome card?
  706.      je     PHP_1        ;  Yes
  707.  
  708.     mov    bh, 1Eh        ; Use Yellow on Blue on color card
  709.  
  710. PHP_1:    int    bios
  711.     call    Locate_PC    ; home cursor
  712.     pop    si        ; point to string again
  713. puthl3:    lodsb            ; get a byte
  714.     cmp    al,0        ; end of string?
  715.     je    puthl4        ; yes, stop
  716.     mov    ah,14
  717.     int    bios        ; else write to screen
  718.     jmp    puthl3        ; and keep going
  719. puthl4:    call    ClrMod_PC        ; Erase any mode line already there
  720.     mov    dx,24 * 100H    ; go to last line
  721.     jmp    PosCur_PC        ; position and return
  722. PutHlp_PC    endp
  723.  
  724. %OUT >> About half way through source file
  725.  
  726. ; Set the baud rate for the current port, based on the value
  727. ; in the portinfo structure.  Returns normally
  728.  
  729. DoBaud_PC    PROC    NEAR
  730.     mov bp,portval
  731.     mov temp1,ax        ; Don't overwrite previous rate. [25]
  732.     mov ax,ds:[bp].baud    ; Check if new rate is valid. [25]
  733.     mov tmp,2
  734.     mul tmp            ; Get index into baud table
  735.     mov bx,offset bddat    ; Start of table
  736.     add bx,ax
  737.     mov ax,[bx]        ; The data to output to port
  738.     cmp ax,0FFH        ; Unimplemented baud rate
  739.     jne dobd0
  740.     mov ax,temp1        ; Get back orginal value
  741.     mov ds:[bp].baud,ax    ; Leave baud rate as is
  742.     mov ah,prstr
  743.     mov dx,offset badbd    ; Give an error message
  744.     int dos
  745.     ret
  746. dobd0:    mov temp1,ax        ; Remember value to output. [25]
  747.     mov dx,modem.mdcom    ; LCR -- Initialize baud rate. [19b]
  748.     in al,dx
  749.     mov bl,al
  750.     or ax,80H
  751.     out dx,al
  752.     mov dx,modem.mddat    ; [19b]
  753.     mov ax,temp1
  754.     out dx,al
  755.     inc dx
  756.     mov al,ah
  757.     out dx,al
  758.     mov dx,modem.mdcom    ; [19b]
  759.     mov al,bl
  760.     out dx,al
  761.     ret
  762. DoBaud_PC    ENDP
  763.  
  764. ; Get the current baud rate from the serial card and set it
  765. ; in the portinfo structure for the current port.  Returns normally
  766. ; This is used during initialization
  767.  
  768. GetBaud_PC    PROC    NEAR
  769.     mov dx,modem.mdcom    ; Get current Line Control Register value
  770.     in al,dx
  771.     mov bl,al        ; Save it
  772.     or ax,80H        ; Turn on to access baud rate generator
  773.     out dx,al
  774.     mov dx,modem.mddat    ; Divisor latch
  775.     inc dx
  776.     in al,dx        ; Get hi order byte
  777.     mov ah,al        ; Save here
  778.     dec dx
  779.     in al,dx        ; Get lo order byte
  780.     push ax
  781.     mov dx,modem.mdcom
  782.     mov al,bl        ; Restore old value
  783.     out dx,al
  784.     pop ax
  785.     cmp ax,0FFFFH        ; Who knows what this is
  786.     je getb2
  787.     mov bx,offset bddat    ; Find rate's offset into table
  788.     mov cl,0        ; Keep track of index
  789. getb0:    cmp ax,[bx]
  790.     je getb1
  791.     inc cl
  792.     cmp cl,baudsiz        ; At the end of the list
  793.     jge getb2
  794.     add bx,2
  795.     jmp getb0
  796. getb1:    mov ch,0
  797.     mov bp,portval
  798.     mov ds:[bp].baud,cx    ; Set baud rate
  799.     ret
  800. getb2:    mov ah,prstr
  801.     mov dx,offset erms40
  802.     int dos
  803.     ret
  804. GetBaud_PC    ENDP
  805.  
  806. ; skip returns if no character available at port,
  807. ; otherwise returns with char in al, # of chars in buffer in dx
  808. PrtChr_PC  PROC    NEAR
  809.     cld            ; Forwards
  810.     call chkxon        ; see if we need to xon
  811.     cmp count,0
  812.     jnz prtch2
  813.     jmp rskp        ; No data - check console
  814. prtch2:    mov si,savesi
  815.     lodsb            ; get a byte
  816.     cmp si,offset source + bufsiz    ; bigger than buffer?
  817.     jb prtch1        ; no, keep going
  818.     mov si,offset source    ; yes, wrap around
  819. prtch1:    dec count
  820.     mov savesi,si
  821.     mov dx,count        ; return # of chars in buffer
  822.     ret
  823. PrtChr_PC  ENDP
  824.  
  825. ; local routine to see if we have to transmit an xon
  826. chkxon    proc    near
  827.     push    bx
  828.     mov    bx,portval
  829.     cmp    [bx].floflg,0    ; doing flow control?
  830.     je    chkxo1        ; no, skip all this
  831.     cmp    xofsnt,false    ; have we sent an xoff?
  832.     je    chkxo1        ; no, forget it
  833.     cmp    count,XOFF_trigger_count ; below trigger?
  834.     jae    chkxo1        ; no, forget it
  835.     mov    ax,[bx].flowc    ; ah gets xon
  836.     call    OutChr_PC    ; send it
  837.      nop
  838.      nop
  839.      nop            ; in case it skips
  840.     mov    xofsnt,false    ; remember we've sent the xon
  841. chkxo1:    pop    bx        ; restore register
  842.     ret            ; and return
  843. chkxon    endp
  844.  
  845. ; Send a break out the current serial port.  Returns normally
  846. SENDBR_PC PROC
  847.     push cx
  848.     push dx
  849.     push ax
  850.     xor cx,cx        ; Clear loop counter
  851.     mov dx,brkadr        ; Port address.  [19b]
  852.     in al,dx        ; Get current setting
  853.     or al,brkval        ; Set send-break bit(s)
  854.     out dx,al        ; Start the break
  855.     push ax
  856.     mov ax,275        ; # of ms to wait
  857.     call pcwait        ; hold break for desired interval
  858.     pop ax
  859.     xor al,brkval        ; Clear send-break bit(s)
  860.     out dx,al        ; Stop the break
  861.     pop ax
  862.     pop dx
  863.     pop cx
  864.     ret            ; And return
  865. SENDBR_PC ENDP
  866.  
  867. ; Wait for the # of milliseconds in ax
  868. ; Thanks to Bernie Eiben for this one
  869. pcwait    proc    near
  870.     mov    cx,240        ; inner loop counter for 1 millisecond
  871.     cmp PC_Subtype, 3    ; Is this an AT?
  872.      jne pcwai1        ;  No
  873.  
  874.     mov cx, 4*240        ; It is an AT, use a much higher value
  875.  
  876. pcwai1:    sub    cx,1        ; inner loop takes 20 clock cycles
  877.     jnz    pcwai1
  878.     dec    ax        ; outer loop counter
  879.     jnz    pcwait        ; wait another millisecond
  880.     ret
  881. pcwait    endp
  882.  
  883. ; Position the cursor according to contents of DX:
  884. ; DH contains row, DL contains column.  Returns normally
  885.  
  886. PosCur_PC    PROC    NEAR
  887.     mov ah,2        ; Position cursor
  888.     mov bh,0
  889.     int bios
  890.     ret
  891. PosCur_PC    ENDP
  892.  
  893. ; Delete a character from the terminal.  This works by printing
  894. ; backspaces and spaces.  Returns normally
  895.  
  896. DoDel_PC    PROC    NEAR
  897.     mov ah,prstr
  898.     mov dx,offset delstr    ; Erase weird character
  899.     int dos        
  900.     ret
  901. DoDel_PC    ENDP
  902.  
  903. ; Move the cursor to the left margin, then clear to end of line
  904. ; Returns normally
  905.  
  906. CtlU_PC    PROC    NEAR
  907.     mov ah,prstr
  908.     mov dx,offset clrlin
  909.     int dos
  910.     call ClearL_PC
  911.     ret
  912. CtlU_PC    ENDP
  913.  
  914. ; set the current port
  915.  
  916. Coms_PC    PROC    NEAR
  917.     mov dx,offset comptab
  918.     mov bx,0
  919.     mov ah,cmkey
  920.     call comnd
  921.      jmp r
  922.     push bx
  923.     mov ah,cmcfm
  924.     call comnd        ; Get a confirm
  925.      jmp comx        ;  Didn't get a confirm
  926.      nop
  927.     pop bx
  928.     mov flags.comflg,bl    ; Set the comm port flag
  929.     cmp flags.comflg,1    ; Using Com 1?
  930.     jne coms0        ; Nope
  931.     mov ax,offset port1
  932.     mov portval,ax
  933.     mov modem.mddat,MDMDAT1    ; Set COM1 defaults
  934.     mov modem.mdstat,MDMSTS1
  935.     mov modem.mdcom,MDMCOM1
  936.     mov modem.mddis,MDMINTC
  937.     mov modem.mden,MDMINTO
  938.     mov modem.mdmeoi,EOICOM
  939.     mov modem.mdintv,MDMINTV
  940.     mov brkadr,MDMCOM1
  941.     ret
  942. coms0:    mov ax,offset port2
  943.     mov portval,ax
  944.     mov modem.mddat,MDMDAT2    ; Set COM2 defaults
  945.     mov modem.mdstat,MDMSTS2
  946.     mov modem.mdcom,MDMCOM2
  947.     mov modem.mddis,MDINTC2
  948.     mov modem.mden,MDINTO2
  949.     mov modem.mdmeoi,EOICOM2
  950.     mov modem.mdintv,MDINTV2
  951.     mov brkadr,MDMCOM2
  952.     ret
  953. comx:    pop bx
  954.     ret
  955. Coms_PC    ENDP
  956.  
  957. ; Set heath emulation on/off
  958.  
  959. VTS_PC    PROC    NEAR
  960.     mov dx,offset ontab
  961.     mov bx,0
  962.     mov ah,cmkey
  963.     call comnd
  964.      jmp r
  965.     push bx
  966.     mov ah,cmcfm
  967.     call comnd        ; Get a confirm
  968.      jmp vt0        ;  Didn't get a confirm
  969.      nop
  970.     pop bx
  971.     mov flags.vtflg,bl    ; Set the VT52 emulation flag
  972.     ret
  973. vt0:    pop bx
  974.     ret
  975. VTS_PC    ENDP
  976.  
  977.  
  978. ; initialization for using serial port.  This routine performs
  979. ; any initialization necessary for using the serial port, including
  980. ; setting up interrupt routines, setting buffer pointers, etc
  981. ; Doing this twice in a row should be harmless (this version checks
  982. ; a flag and returns if initialization has already been done)
  983. ; SerRst_PC below should restore any interrupt vectors that this changes
  984. ; Returns normally
  985.  
  986. SerIni_PC PROC
  987.  
  988.     push es
  989.     cmp portin, 0        ; Did we initialize port already? [21c]
  990.      jne serin0        ;  Yes, so just leave. [21c]
  991.  
  992.     call NoInt        ; Disable interrupts
  993.  
  994.     xor ax,ax        ; Address low memory
  995.     mov es,ax
  996.  
  997.     mov bx,modem.mdintv    ; Save serial card interrupt vector. [19b]
  998.     mov ax,es:[bx]
  999.     mov savsci,ax
  1000.  
  1001.     mov ax,offset SerInt    ; And point it to my routine
  1002.     mov es:[bx],ax
  1003.  
  1004.     add bx,2        ; Save CS register too. [19b]
  1005.  
  1006.     mov ax,es:[bx]
  1007.     mov savscs,ax
  1008.     mov es:[bx],cs
  1009.  
  1010.     mov portin,1        ; Remember port has been initialized
  1011.  
  1012.     call ClrBuf_PC        ; Clear input buffer
  1013.  
  1014.     mov ax,modem.mdstat
  1015.     mov mst,ax        ; Use this address for status
  1016.  
  1017.     mov ax,modem.mddat
  1018.     mov mdat,ax        ; Use this address for data
  1019.  
  1020.     mov al,modem.mdmeoi
  1021.     mov mdeoi,al        ; Use to signify end-of-interrupt
  1022.  
  1023.     in al,21H        ; Set up 8259 interrupt controller
  1024.     and al,modem.mden    ; Enable INT3 or INT4
  1025.     out 21H,al
  1026.  
  1027.     mov dx,modem.mdcom    ; Set up the serial card
  1028.     mov al,3
  1029.     out dx,al
  1030.  
  1031.     mov dl,0F9h
  1032.     mov al,1        ; Set up interrupt enable register
  1033.     out dx,al
  1034.  
  1035.     mov dl,0FCh        ; Enable interrupts from serial card
  1036.     mov al,0Bh
  1037.     out dx,al
  1038.  
  1039.     call OkInt        ; Allow interrupts
  1040.  
  1041.     mov dl,0F8h
  1042.     in al,dx
  1043.  
  1044. serin0:    pop es
  1045.     ret
  1046.  
  1047. SerIni_PC ENDP
  1048.  
  1049.  
  1050. ; Reset the serial port.  This is the opposite of SerIni_PC.  Calling
  1051. ;  this twice without intervening calls to SerIni_PC should be harmless.
  1052. ; Returns normally.
  1053.  
  1054. SerRst_PC PROC
  1055.  
  1056.     push es            ; Preserve this
  1057.     cmp portin,0        ; Reset already?
  1058.      je srst1        ;  Yes, just leave
  1059.  
  1060.     call NoInt        ; Disable interrupts
  1061.  
  1062.     mov dx, 03FCh        ; Disable modem interrupts, assume port 1
  1063.     cmp flags.comflg, 1    ; Is it port 1?
  1064.      je srst0        ;  Yes
  1065.  
  1066.     mov dh, 2        ; Port 2
  1067.  
  1068. srst0:    mov al, 3
  1069.     out dx,al
  1070.  
  1071.     in al, 21h        ; Interrupt controller
  1072.  
  1073.     or al, modem.mddis    ; Inhibit IRQ3 or IRQ4
  1074.     out 21H, al
  1075.  
  1076.     xor bx, bx        ; Address low memory
  1077.     mov es, bx
  1078.  
  1079.     mov bx, modem.mdintv    ; Restore the serial card int vector
  1080.     mov ax, savsci
  1081.     mov es:[bx], ax
  1082.  
  1083.     add bx, 2        ; Restore CS too
  1084.  
  1085.     mov ax, savscs
  1086.     mov es:[bx], ax
  1087.     mov portin, 0        ; Reset flag
  1088.  
  1089.     call OkInt
  1090.  
  1091. srst1:    pop es
  1092.     ret            ; All done
  1093.  
  1094. SerRst_PC ENDP
  1095.  
  1096.  
  1097. Drop_DTR_PC PROC
  1098.  
  1099.     push ax            ; Save regs
  1100.     push dx
  1101.  
  1102.     mov dx, 03FCh        ; Port for COM1 modem control register
  1103.     cmp flags.comflg, 1    ; Using port 1 ?
  1104.      je DTR_0        ;  Yes, continue
  1105.  
  1106.     mov dh, 2        ; Using COM2
  1107.  
  1108. DTR_0:    sub al, al        ; Clear this register
  1109.     out dx,al        ; Drop DTR now
  1110.  
  1111.     pop dx            ; Restore regs
  1112.     pop ax
  1113.     ret            ; Done here
  1114.  
  1115. Drop_DTR_PC ENDP
  1116.  
  1117.  
  1118. ;   Serial port interrupt routine
  1119.  
  1120. SERINT  PROC FAR
  1121.  
  1122. ; Save some registers ...
  1123.     push dx
  1124.     push ds
  1125.     push ax
  1126.     push es
  1127.  
  1128.     mov ax, SEG DataS    ; Address data segment
  1129.     mov ds, ax        ; Set up ds
  1130.     mov es, ax        ;  and es
  1131.  
  1132.     mov dx, mst        ; Line Status Register (LSR), for port 1 or 2
  1133.     in al, dx
  1134.  
  1135.     test al, mdminp        ; Data available?
  1136.      jz Return_2        ;  Nope
  1137.  
  1138.     mov dx, mdat        ; Get the data
  1139.     in al,dx
  1140.  
  1141.     cmp Count, BufSiz    ; Room left in buffer?
  1142.      jae Return_2        ;  No room left, don't overstore!!
  1143.  
  1144. ; Save more registers ...
  1145.     push bx
  1146.     push di
  1147.     push bp
  1148.  
  1149.     mov bp, portval
  1150.     cmp ds:[bp].floflg, 0    ; Doing flow control?
  1151.      je srint2        ;  Nope
  1152.  
  1153.     mov bx, ds:[bp].flowc    ; Flow control char (BH = XON, BL = XOFF)
  1154.     cmp al, bl        ; Is it an XOFF?
  1155.      jne srint1        ;  Nope, go on
  1156.  
  1157.     mov xofrcv, true    ; Set the flag
  1158.     jmp SHORT RetInt
  1159.  
  1160. srint1:    cmp al, bh        ; Get an XON?
  1161.      jne srint2        ;  No, go on
  1162.  
  1163.     mov xofrcv, false    ; Clear our flag
  1164. ;    jmp SHORT RetInt
  1165.  
  1166. RetInt:
  1167.  
  1168. ; Restore some saved registers ...
  1169.     pop bp
  1170.     pop di
  1171.     pop bx
  1172.  
  1173. Return_2:
  1174.     sti            ; Allow ints now
  1175.     mov al, mdeoi        ; Send End-of-Interrupt ...
  1176.     out intcon1, al        ;  to 8259
  1177.  
  1178. ; Restore other saved registers ...
  1179.     pop es
  1180.     pop ax
  1181.     pop ds
  1182.     pop dx
  1183.  
  1184.     iret            ; Return from interrupt
  1185.  
  1186. srint2:    cld            ; Store forwards
  1187.     mov di, srcpnt        ; Where to store it
  1188.     stosb            ; Store it
  1189.  
  1190.     cmp di, OFFSET Source + BufSiz
  1191.      jb srint3        ;  Not past end ...
  1192.  
  1193.     mov di, OFFSET Source    ; Wrap buffer around
  1194.  
  1195. srint3:    inc count        ; Bump the count
  1196.     mov srcpnt, di        ; Store the updated pointer
  1197.  
  1198.     cmp ds:[bp].floflg, 0    ; Doing flow control?
  1199.      je RetInt        ;  No, just leave
  1200.  
  1201.     cmp count, XOFF_trigger_count ; Past the high trigger point?
  1202.      jbe RetInt        ;  No, we're within our limit
  1203.  
  1204.     cmp xofsnt, true    ; Have we sent an XOFF?
  1205.      je RetInt        ;  Yes
  1206.  
  1207.     mov ah,bl        ; Get the XOFF
  1208.     push cx            ; OutChr_PC clobbers cx, we're not allowed to
  1209.     call OutChr_PC        ; Send it
  1210.      nop
  1211.      nop
  1212.      nop
  1213.     pop cx            ; Restore cx
  1214.  
  1215.     mov xofsnt,true        ; Remember we sent it
  1216.     jmp SHORT RetInt    ; Branch upwards into common code
  1217.  
  1218. SERINT    ENDP
  1219.  
  1220.  
  1221. ; Produce a short beep.  The PC DOS bell is long enough to cause a loss
  1222. ; of data at the port.  Returns normally
  1223.  
  1224. Beep_PC    PROC    NEAR
  1225.     mov al,10110110B    ; Gen a short beep (long one losses data.)
  1226.     out timer+3,al        ; Code snarfed from Technical Reference
  1227.     mov ax,533H
  1228.     out timer+2,al
  1229.     mov al,ah
  1230.     out timer+2,al
  1231.     in al,port_b
  1232.     mov ah,al
  1233.     or al,03
  1234.     out port_b,al
  1235.     sub cx,cx
  1236.     mov bl,1
  1237. beep0:  loop beep0
  1238.     dec bl    
  1239.     jnz beep0
  1240.     mov al,ah
  1241.     out port_b,al
  1242.     ret
  1243. Beep_PC    ENDP
  1244.  
  1245. ; put the number in ax into the buffer pointed to by di.  Di is updated
  1246. nout    proc    near
  1247.     cld            ; Forwards
  1248.     mov    dx,0        ; high order is always 0
  1249.     mov    bx,10
  1250.     div    bx        ; divide to get digit
  1251.     push    dx        ; save remainder digit
  1252.     or    ax,ax        ; test quotient
  1253.     jz    nout1        ; zero, no more of number
  1254.     call    nout        ; else call for rest of number
  1255. nout1:    pop    ax        ; get digit back
  1256.     add    al,'0'        ; make printable
  1257.     stosb            ; drop it off
  1258.     ret            ; and return
  1259. nout    endp
  1260.  
  1261.  
  1262. ; Jumping to this location is like retskp.  It assumes the instruction
  1263. ;   after the call is a jmp addr
  1264.  
  1265. RSKP    PROC    NEAR
  1266.     pop bp
  1267.     add bp,3
  1268.     push bp
  1269. ;    ret
  1270. RSKP    ENDP
  1271.  
  1272. ; Jumping here is the same as a ret
  1273.  
  1274. R    PROC    NEAR
  1275.     ret
  1276. R    ENDP
  1277.  
  1278. Code    ENDS
  1279.  
  1280.     END
  1281. 
  1282.